package com.mall.annotation;

import com.mall.db.service.OperationLogService;
import com.wxd.utils.IpUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

@Aspect
@Component
public class OperationLogAspect {

    @Resource(name = "operationLogService")
    private OperationLogService ols;

    //切入点，利用自定义注解作为切入的位置，即自定义注解的地方的那个方法就是切入点
    @Pointcut("@annotation(com.mall.annotation.OperationLog)")
    public void pointcut(){}

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point){
        Object result = null;
        //记录执行开始时间
        long beginTime = System.currentTimeMillis();
        try {
            //执行方法
            result = point.proceed();


        }catch (Throwable e){
            e.printStackTrace();
        }
        //执行完成后的时间
        long endTime = System.currentTimeMillis();

        System.out.println("执行所要的时间："+(endTime-beginTime));

        saveOperationLog(point,result);

        return result;
    }

    private void saveOperationLog(ProceedingJoinPoint point,Object result){
        //获取注解描述，就是注解传入的值
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();//获取执行的方法
        OperationLog ol = method.getAnnotation(OperationLog.class);//获取注解类对象
        com.mall.db.domain.OperationLog log = new com.mall.db.domain.OperationLog();
        if (ol!=null){
            log.setAction(ol.value());
            log.setType(ol.type());

        }
        //获取request
        HttpServletRequest request = getRequest();


        log.setUser("admin"); //TODO 登录用户信息
        log.setIp(IpUtils.getIpAddress(request));

        //获取执行的方法
        String className = point.getTarget().getClass().getName();
        String methodName = signature.getName();
        log.setMethod(className+"."+methodName+"()");

        //获取执行方法中的参数及参数值
        Object[] args = point.getArgs();
        LocalVariableTableParameterNameDiscoverer l = new LocalVariableTableParameterNameDiscoverer();
        String []paramNames = l.getParameterNames(method);
        if (args!=null && paramNames !=null){
            String param = "";
            int i = 0;
            for (Object arg:args){
                param += (i==0?"":",")+paramNames[i] + ":" + args[i];
                i++;
            }
            log.setParams(param);
        }

        //把执行结果转换为Map
        Map<String,Object> res = (Map<String, Object>) result;
        if (!StringUtils.isEmpty(res.get("is"))){

            log.setResult(res.get("is")+"");

        }
        if (!StringUtils.isEmpty(res.get("msg"))){

            log.setComment(res.get("msg")+"");

        }

        log.setCreateTime(new Date());
        //执行日志保存
        ols.save(log);

    }

    /**
     * 获取request的方法
     * @return
     */
    public HttpServletRequest getRequest(){
        return ((ServletRequestAttributes)Objects.
                requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    }
}

